<!DOCTYPE html>
<html lang="en">
    <head>
        <title>
            Practical introduction to Qt in Python
        </title>
        <meta charset="utf-8">
        <meta name="description"
              content="This tutorial show how to create a multimedia player
                       while you learn the basis of Qt framework programming
                       under the Python programming language." />
        <meta name="keywords"
              content="Python,Qt,tutorial,programming,multimedia player" />
        <meta name="author"
              content="Gonzalo Exequiel Pedone" />
        <link type="text/css"
              rel="stylesheet"
              href="syntaxhighlighter/styles/shCoreDefault.css" />
        <link rel="stylesheet"
              href="styles/print.css"
              type="text/css"
              media="print" />
        <link rel="stylesheet"
              href="styles/screen.css"
              type="text/css"
              media="screen" />
        <script type="text/javascript"
                src="syntaxhighlighter/scripts/shCore.js"></script>
        <script type="text/javascript"
                src="syntaxhighlighter/scripts/shBrushPython.js"></script>
        <script type="text/javascript"
                src="scripts/highlighter.js"></script>
    </head>
    <body>
        <div class="page">
            <div class="title">
                Practical introduction to Qt in Python
            </div>
            <div class="license">
                <a target="_blank"
                   rel="license"
                   href="http://creativecommons.org/licenses/by-sa/3.0/">
                    <img class="thumbnail"
                         alt="Creative Commons License"
                         src="pics/cc3.0-by-sa-88x31.png" />
                </a><br />
                <span xmlns:dct="http://purl.org/dc/terms/"
                      href="http://purl.org/dc/dcmitype/Text"
                      property="dct:title"
                      rel="dct:type">
                    Practical introduction to Qt in Python
                </span> by
                <a target="_blank"
                   href="http://hipersayanx.blogspot.com/"
                   xmlns:cc="http://creativecommons.org/ns#"
                   property="cc:attributionName"
                   rel="cc:attributionURL">
                    Gonzalo Exequiel Pedone</a>
                is licensed under a
                <a target="_blank"
                   rel="license"
                   href="http://creativecommons.org/licenses/by-sa/3.0/">
                    Creative Commons Attribution-ShareAlike 3.0 Unported
                </a>.
            </div>
        </div>
        <div class="page">
            <h1>Content index</h1>
            <ul>
                <li>
                    <a href="#intro">
                        Intro
                    </a>
                </li>
                <li>
                    <a href="#tools">
                        The tools
                    </a>
                </li>
                <li>
                    <a href="#designer">
                        Designing the Graphical User Interface
                    </a>
                </li>
                <li>
                    <a href="#code">
                        The code
                    </a>
                </li>
                <li>
                    <a href="#menubuttons">
                        Menu Buttons
                    </a>
                </li>
                <li>
                    <a href="#signalsandslots">
                        Signals and slots
                    </a>
                </li>
                <li>
                    <a href="#addfilesplaylist">
                        Add files to the playlist
                    </a>
                </li>
                <li>
                    <a href="#playfiles">
                        Play files
                    </a>
                </li>
                <li>
                    <a href="#timers">
                        Using timers
                    </a>
                </li>
                <li>
                    <a href="#fullscreen">
                        Go fullscreen
                    </a>
                </li>
                <li>
                    <a href="#aspectratio">
                        Video aspect ratio
                    </a>
                </li>
                <li>
                    <a href="#playpause">
                        Play and pause
                    </a>
                </li>
                <li>
                    <a href="#shufflerepeat">
                        Shuffle and repeat the playlist
                    </a>
                </li>
                <li>
                    <a href="#seekmedia">
                        Move forward and backward the medias
                    </a>
                </li>
                <li>
                    <a href="#clearplaylist">
                        Removing the medias from playlist
                    </a>
                </li>
                <li>
                    <a href="#addurlplaylist">
                        Add URLs to the playlist
                    </a>
                </li>
                <li>
                    <a href="#about">
                        The "About" dialog
                    </a>
                </li>
                <li>
                    <a href="#stylesheets">
                        Using stylesheets
                    </a>
                </li>
                <li>
                    <a href="#internationalisation">
                        Internationalisation
                    </a>
                </li>
                <li>
                    <a href="#relatedlinks">
                        Links of interest
                    </a>
                </li>
            </ul>
        </div>
        <div class="page">
            <h1><a name="intro">Intro</a></h1>
            <p>
                This tutorial pretends to be a brief introduction to the
                Graphics User Interfaces (GUI) programming, using the Python
                programming lenguage and Qt framework, both multiplataform.
            </p>
            <p>
                In this tutorial we'll use PyQt to show you the base of Qt
                programming under Pyhon.
            </p>
            <p>
                To make this tutorial even more funny, because you can learn the
                theorical side of Qt programming just reading the documentation,
                I will focus it only in the practical side, therefore I deside
                to show you how to create a video player, which its programming
                is unbelievably simple with Qt. For better understanding of what
                I mean, see the image below:
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot001.png">
                    <img class="thumbnail-75"
                         alt="final result"
                         src="pics/snapshots/snapshot001.png" />
                </a>
            </p>
            <p>
                If this is interesting for you, continue reading.
            </p>
        </div>
        <div class="page">
            <h1><a name="tools">
                The tools
            </a></h1>
            <p>
                The first step is to download all tool needed fot creating our
                PyQt programs.
            </p>
            <p>
                This tutorial is thought for people that already have knowledge
                of Python programming, you can download it from here if you
                haven't installed yet:
            </p>
            <p class="space"></p>
            <p>
                <a target="_blank"
                   href="http://www.python.org/download/">
                    www.python.org/download
                </a>
            </p>
            <p class="space"></p>
            <p>
                Now we need to download the Qt bindings for using it inside
                Python, we will use PyQt. You can download it from here:
            </p>
            <p class="space"></p>
            <p>
                <a target="_blank"
                   href="http://www.riverbankcomputing.co.uk/software/pyqt/download">
                    www.riverbankcomputing.co.uk/software/pyqt/download
                </a>
            </p>
            <p class="space"></p>
            <p>
                In this tutorial I decided to use <a target="_blank"
                href="http://ninja-ide.org/">Ninja IDE</a> as development
                environment, to make the development agile and consistent
                between various working environments (operative systems,
                graphics environments, etc.). Download Ninja IDE from here:
            </p>
            <p class="space"></p>
            <p>
                <a target="_blank"
                   href="http://ninja-ide.org/downloads.html">
                    ninja-ide.org/downloads.html
                </a>
            </p>
            <p class="space"></p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot002.png">
                    <img class="thumbnail-75"
                         alt="Ninja IDE"
                         src="pics/snapshots/snapshot002.png" />
                </a>
            </p>
        </div>
        <div class="page">
            <h1><a name="designer">
                Designing the Graphical User Interface
            </a></h1>
            <p>
                Let's start with the easy part, the design of the GUI. We will
                use Qt Designer which comes with the PyQt installation packages
                of Mac and Windows, or as dependency in GNU/Linux.
            </p>
            <p>
                We must open Qt Designer from the Start menu.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot003.png">
                    <img class="thumbnail"
                         alt="Open Qt Designer"
                         src="pics/snapshots/snapshot003.png" />
                </a>
            </p>
            <p>
                When you open Qt Designer, it show a dialog to select the type
                of window that will use our program, depending of the type of
                window you select, the window manager of the graphics
                environment, will treat the program window in one way or
                another, we have three types of windows to choose from:
            </p>
            <ul>
                <li>
                    <strong>Main Window</strong>: As its name implies, has
                    special properties that treat it as such by the window
                    manager.
                </li>
                <li>
                    <strong>Dialog</strong>: It is more suitable for use as
                    children of another window, for instance, configuration
                    dialogs, "About" dialog, etc..
                </li>
                <li>
                    <strong>Widget</strong>: It can be a window or generic
                    graphic element, roughly, a widget is a graphic element that
                    interacts with the user, for instance, buttons, selection
                    boxes, text boxes, etc.. In turn a widget can be a container
                    for other widgets, and a widget without a container is
                    always a independent window, in this case, this widget is
                    treated as a generic window.
                </li>
            </ul>
        </div>
        <div class="page">
            <p>
                In this case we select "Main Window".
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot004.png">
                    <img class="thumbnail-75"
                         alt="Select Main Window"
                         src="pics/snapshots/snapshot004.png" />
                </a>
            </p>
            <p>
                Here we create an interface as simple as possible, with direct
                access to the most common options, to gain more space will
                remove the menu bar and the status bar.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot005.png">
                    <img class="thumbnail-75"
                         alt="Remove menu and status bar"
                         src="pics/snapshots/snapshot005.png" />
                </a>
            </p>
        </div>
        <div class="page">
            <p>
                Now we begin to drag widgets from the Widget Box and drop them
                into the window.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot006.png">
                    <img class="thumbnail-75"
                         alt="Drag&and;drop widgets"
                         src="pics/snapshots/snapshot006.png" />
                </a>
            </p>
            <p>
                In general the most popular options that every video player must
                have are (in my opinion):
            </p>
            <ul>
                <li>
                    An area to show the video
                    (<strong>Phonon::VideoPlayer</strong>).
                </li>
                <li>
                    A bar that displays the playlist and their options
                    (<strong>Dock Widget</strong>).
                </li>
                <li>
                    Play/Pause, Stop, Previous and Next media buttons
                    (<strong>Push Button</strong>).
                </li>
                <li>
                    A control for adjusting the volume, and another to forward
                    and rewind the media manually
                    (<strong>phonon::VolumeSlider</strong> and
                    <strong>phonon::SeekSlider</strong>).
                </li>
                <li>
                    An area to show the playtime of the media
                    (<strong>Label</strong>).
                </li>
                <li>
                    A button to put the player in fullscreen mode.
                </li>
                <li>
                    A button to change the space occupied by the video within
                    the video widget.
                </li>
                <li>
                    Un button to show or hide the playlist.
                </li>
                <li>
                    And finally the "About" button.
                </li>
            </ul>
            <p>
                Put all these controls (except for
                <strong>Phonon::VideoPlayer</strong>) inside a
                <strong>Widget</strong>. It may look similar to this:
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot007.png">
                    <img class="thumbnail-75"
                         alt="Widgets position"
                         src="pics/snapshots/snapshot007.png" />
                </a>
            </p>
        </div>
        <div class="page">
            <p>
                As you can see, I changed the text of the buttons and labels.
                You can change the text with a double click over it and
                writing a new text. The title of the playlist is changed with
                the <strong>windowTitle</strong> property.
            </p>
            <p>
                Now we will test the GUI, to activate the preview press CTRL+R.
                In the preview we interact with the window and its widgets in
                the same way we would in the finished program, we can press
                buttons, move sliders, move the dock, resize the window, etc.,
                Of course, the preview has not all the functionality that you
                will have in the finished program.
            </p>
            <p>
                If you resize the window, the widgets remain fixed, and that her
                size and its position does not fit the window size, except the
                dock.
            </p>
            <p>
                To fix this problem, right click on any empty area that contains
                the widgets -&gt; Lay out -&gt; Lay out in a grid.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot008.png">
                    <img class="thumbnail-75"
                         alt="Lay out in a grid"
                         src="pics/snapshots/snapshot008.png" />
                </a>
            </p>
            <p>
                Now let's design the playlist bar. Just as we did with the
                window, drag and drop the widgets into the Dock.
            </p>
            <p>
                The widgets to use are:
            </p>
            <ul>
                <li>
                    <strong>List Widget</strong>, here is show all files and
                    URLs to play.
                </li>
                <li>
                    A button to add new medias, we can add local files, and also
                    web addresses for radio and television over the Internet
                    (online streaming).
                </li>
                <li>
                    A button for shuffling and other for repeating the playlist.
                </li>
                <li>
                    A button to remove the selected media and another to clear
                    the entire playlist.
                </li>
                <li>
                    Also add two <strong>Horizontal Spacer</strong> to separate
                    and keep sorted the different groups of features.
                </li>
            </ul>
        </div>
        <div class="page">
            <p>
                Finally, we arrange the widgets in a grid as we did before, as
                in the image below:
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot009.png">
                    <img class="thumbnail-75"
                         alt="Final widgets position"
                         src="pics/snapshots/snapshot009.png" />
                </a>
            </p>
            <p>
                Now let's make the interface more intuitive and less dependent
                on language, rather than using words, letters or symbols on the
                buttons, we use icons.
            </p>
            <p>
                To do this, double click on each button and delete the text,
                then in the property bar, change the
                <strong>maximumSize</strong> property to 24x24, and in the
                <b>icon</b> property, press the down arrow and select
                "Choose File...".
            </p>
            <p>
                The order of the icons from left to right are:
            </p>
            <table>
                <thead>
                    <th class="texttoleft">
                        Name
                    </th>
                    <th>
                        Icon
                    </th>
                    <th>
                        Alternative
                    </th>
                    <th>
                        Checkable
                    </th>
                </thead>
                <tbody>
                    <tr>
                        <td>
                            Play/Pause
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Play"
                                 src="../share/icons/media-playback-start.png">
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Pause"
                                 src="../share/icons/media-playback-pause.png">
                        </td>
                        <td class="centercell">
                            <strong>Yes</strong>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Stop
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Pause"
                                 src="../share/icons/media-playback-stop.png">
                        </td>
                        <td class="centercell">
                        </td>
                        <td class="centercell">
                            No
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Skip Backward
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Skip backward"
                                 src="../share/icons/media-skip-backward.png">
                        </td>
                        <td class="centercell">
                        </td>
                        <td class="centercell">
                            No
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Skip Forward
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Skip forward"
                                 src="../share/icons/media-skip-forward.png">
                        </td>
                        <td class="centercell">
                        </td>
                        <td class="centercell">
                            No
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Fullscreen
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Fullscreen"
                                 src="../share/icons/view-fullscreen.png">
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="View restore"
                                 src="../share/icons/view-restore.png">
                        </td>
                        <td class="centercell">
                            <strong>Yes</strong>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            About
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="About"
                                 src="../share/icons/help-about.png">
                        </td>
                        <td class="centercell">
                        </td>
                        <td class="centercell">
                            No
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Add media
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Add media"
                                 src="../share/icons/list-add.png">
                        </td>
                        <td class="centercell">
                        </td>
                        <td class="centercell">
                            No
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Shuffle playlist
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Playlist shuffle"
                                 src="../share/icons/media-playlist-shuffle.png">
                        </td>
                        <td class="centercell">
                        </td>
                        <td class="centercell">
                            <strong>Yes</strong>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Repeat playlist
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Playlist repeat"
                                 src="../share/icons/media-playlist-repeat.png">
                        </td>
                        <td class="centercell">
                        </td>
                        <td class="centercell">
                            <strong>Yes</strong>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Remove selectd medias
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Remove media"
                                 src="../share/icons/list-remove.png">
                        </td>
                        <td class="centercell">
                        </td>
                        <td class="centercell">
                            No
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Clear playlist
                        </td>
                        <td class="centercell">
                            <img class="thumbnail"
                                 alt="Playlist clear"
                                 src="../share/icons/edit-clear.png">
                        </td>
                        <td class="centercell">
                        </td>
                        <td class="centercell">
                            No
                        </td>
                    </tr>
                </tbody>
            </table>
            <p>
                You can setup the icon of the button with the
                <strong>icon</strong> property. the <strong>icon</strong>
                property offers several icon styling depending on the button
                status, but only two status are of our interest:
            </p>
            <ul>
                <li>
                    <strong>Normal Off</strong>: This is the status of the
                    button when is not pressed or checked.
                </li>
                <li>
                    <strong>Normal On</strong>: This is the status of the
                    button when is pressed or checked. Here we will setup the
                    alternative icon.
                </li>
            </ul>
        </div>
        <div class="page">
            <p>
                Now let's set the the playlist appearance.
            </p>
            <p>
                In <strong>features</strong> property, check
                <em>DockWidgetMovable</em> and <em>DockWidgetFloatable</em> and
                uncheck the rest, these properties indicate that we can move and
                separate the playlist respectively inside and outside the
                window, but not close or change their appearance, among other
                things.
            </p>
            <p>
                In <strong>allowedAreas</strong> property, mark
                <em>LeftDockWidgetArea</em> and <em>RightDockWidgetArea</em> and
                uncheck the rest, these properties indicate that we can only
                move the playlist to left or right respectively within the
                window, but never to top or bottom.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot010.png">
                    <img class="thumbnail-75"
                         alt="Widget properties"
                         src="pics/snapshots/snapshot010.png" />
                </a>
            </p>
        </div>
        <div class="page">
            <p>
                The interface of our video player is almost finished, we just
                need to rename the widgets that for an easy access from the
                code. To do this just click on the widget you want to change
                the name, and in the "Object Inspector" bar, double click on the
                selected object to change its name.
            </p>
            <p>
                Usually, the names of the widgets start with three letters
                indicating the type of widget, followed by the name or action
                performed by that widget, where each word is capitalized, for
                example:
            </p>
            <p class="space"></p>
            <p>
                <em>btn</em><strong>PlayPause</strong> → <em>btn</em> = Button,
                <strong>PlayPause</strong> = Play or Pause.
            </p>
            <p class="space"></p>
            <p>
                In this tutorial the used prefixes are:
            </p>
            <ul>
                <li>
                    btn → Button
                </li>
                <li>
                    cbx → Combo Box
                </li>
                <li>
                    lbl → Label
                </li>
                <li>
                    sld → Slider
                </li>
                <li>
                    vdp → Video Player
                </li>
                <li>
                    hsp → Horizontal Spacer
                </li>
                <li>
                    lsw → List Widget
                </li>
            </ul>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot011.png">
                    <img class="thumbnail-50"
                         alt="Object Inspector"
                         src="pics/snapshots/snapshot011.png" />
                </a>
            </p>
            <p>
                And finally we can test the finished GUI with Ctrl+R.
            </p>
        </div>
        <div class="page">
            <h1><a name="code">
                The code
            </a></h1>
            <p>
                Once finished the GUI design, we must complete our program
                functionality through the code.
            </p>
            <p>
                Since this tutorial is intended to cover as many users on
                multiple operating systems, and also to standardize a bit the
                development process, we will use IDE Ninja to develop the full
                program.
            </p>
            <p>
                So to start, open Ninja IDE.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot012.png">
                    <img class="thumbnail"
                         alt="Open Ninja IDE"
                         src="pics/snapshots/snapshot012.png" />
                </a>
            </p>
            <p>
                As soon Ninja IDE is opened, it shows a nice welcome screen,
                press the second icon in the toolbar to create a new project.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot013.png">
                    <img class="thumbnail"
                         alt="Ninja IDE toolbar"
                         src="pics/snapshots/snapshot013.png" />
                </a>
            </p>
        </div>
        <div class="page">
            <p>
                Select the option to create a Python project.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot014.png">
                    <img class="thumbnail"
                         alt="Select project type"
                         src="pics/snapshots/snapshot014.png" />
                </a>
            </p>
            <p>
                Introduce the program data and press <b>Finish</b>. Fields
                marked with an asterisk (*) are required fields.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot015.png">
                    <img class="thumbnail"
                         alt="Fill project data"
                         src="pics/snapshots/snapshot015.png" />
                </a>
            </p>
        </div>
        <div class="page">
            <p>
                When we finish creating the project, the project folder and a
                file <em>__ init__.py</em> file appear in the project bar.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot016.png">
                    <img class="thumbnail"
                         alt="Remove __ init__.py file"
                         src="pics/snapshots/snapshot016.png" />
                </a>
            </p>
            <p>
                But, what is that <em>__ init__.py</em> file?
            </p>
            <p>
                Files with the <em>__init__.py</em> name are used to mark the
                directories on the disk as a Python package directory. If you
                have the files:
            </p>
            <pre>
mydir/spam/__init__.py
mydir/spam/module.py
            </pre>
            <p>
                and <em>mydir</em> is the working path of your project, then you
                can import the module <em>module.py</em> as:
            </p>
            <pre class="brush: py;">
import spam.module
            </pre>
            <p>
                or
            </p>
            <pre class="brush: py;">
from spam import module
            </pre>
            <p>
                If you delete the <em>__init__.py</em>, Python will no look for
                submodules in that directory, so Python will fail when trying to
                import that module.
            </p>
            <p>
                The <em>__init__.py</em> file is usually empty, but can be used
                to export selected parts of the package under certain names,
                store certain functions, etc.. Considering the above example,
                the contents of the <em>__init__.py</em> module can be accessed
                as:
            </p>
            <pre class="brush: py;">
import spam
            </pre>
            <p>
                Related link:
            </p>
            <p class="space"></p>
            <p>
                <a target="_blank"
                   href="http://effbot.org/pyfaq/what-is-init-py-used-for.htm">
                    effbot.org/pyfaq/what-is-init-py-used-for.htm
                </a>
            </p>
            <p class="space"></p>
            <p>
                In this tutorial we will not use the <em>__init__.py</em> files,
                so we can delete them.
            </p>
            <p>
                Now let's build the directory tree of the project. For instance,
                start by creating the <em>src</em> folder where will put the
                source code of the program, to do this right click on the
                project folder, and select <strong>Add New Folder</strong>.
            </p>
            <p>
                Write the name of the folder and press <strong>OK</strong>.
            </p>
            <p>
                To create a subpath, right click on the folder where you want to
                create a subpath and select the corresponding option.
            </p>
        </div>
        <div class="page">
            <p>
                The directory tree of the project should be as follows:
            </p>
            <ul>
                <li>
                    <em>PythonQtVideoPlayer/share/icons</em> → Here we place
                    all the program icons.
                </li>
                <li>
                    <em>PythonQtVideoPlayer/share/ui</em> → Here we will place
                    the interfaces files created with Qt Designer.
                </li>
                <li>
                    <em>PythonQtVideoPlayer/src</em> → Here will place the
                    source code of the program.
                </li>
            </ul>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot017.png">
                    <img class="thumbnail"
                         alt="Project structure"
                         src="pics/snapshots/snapshot017.png" />
                </a>
            </p>
            <p>
                Inside the <em>src</em> folder, create a file named
                <em>videoplayer.py</em> in which will put the code below, that
                is the minimum initialization code needed to run the program.
                The explanation of each line is included as comments in the
                code.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 24-24
# Import the "sys" module for passing the command line arguments to Qapplication.
import sys

# src/videoplayer.py: 31-44
# The "QtCore" module is the basis for the rest of the Qt modules, it gives access
# to all functionalities of Qt that doesn't requires the initialisation of the
# graphics system.
# The "QtGui" module gives access to all functionalities for creating the graphics
# user interface for our apps, for instance, the widgets, the dialogs, OpenGL
# graphic widgets, etc..
# The "uic" module is exclusive of PyQt. Among other things, this module can
# read and create the graphic interface from a .ui on run time, it also can
# create source code for the GUI from the .ui files.
# .ui files are XML files that defines the attributes and actions of each widget
# into the GUI.
# The phonon module give access to all multimedia functionalities, such as
# music, video, pictures and online streamming play.
from PyQt4 import QtCore, QtGui, uic, phonon
            </pre>
        </div>
        <div class="page">
            <pre class="brush: py;">
# src/videoplayer.py: 51-59
# The VideoPlayer class will be a wrapper for MainWindow.
class VideoPlayer(QtGui.QMainWindow):
    def __init__(self):
        # First, we must initialize the constructor of the ancestor class.
        QtGui.QMainWindow.__init__(self)

        # Load the GUI from videoplayer.ui. now, "self" is like as a pointer to
        # MainWindow.
        uic.loadUi('../share/ui/videoplayer.ui', self)


# src/videoplayer.py: 558-571
# Python does not uses or requires any special main block for executing the
# code. But, under some circumstances could be useful putting the codeto run
# inside of an "if" block that checks the __name__ global variable, if we are
# executing the module alone, __name__ will be equal to '__main__', otherwise,
# if the module is called by other module, __name__ will be equal to te name of
# the calling module.
# This is useful in unitary tests in which we can test each of this modules
# without executing the whole program.
if __name__ == '__main__':
    # Always, before calling a Qt object, you must create an instance of
    # QApplication, which will receive the command line argumments, initialize
    # the working environment, set some global variables, and controls the main
    # loop.
    app = QtGui.QApplication(sys.argv)

    # src/videoplayer.py: 589-593
    # Set the program name as it will appear in the task manager.
    app.setApplicationName('QtVideoPlayer')

    # Create an instance of VideoPlayer.
    videoPlayer = VideoPlayer()

    # src/videoplayer.py: 602-606
    # Show the main window of our program.
    videoPlayer.show()

    # Execute the main loop.
    app.exec_()
            </pre>
            <p>
                Now we can run the program by pressing the green arrow in Ninja
                IDE.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot018.png">
                    <img class="thumbnail"
                         alt="Running the program"
                         src="pics/snapshots/snapshot018.png" />
                </a>
            </p>
        </div>
        <div class="page">
            <p>
                If this is the first time you run the program a dialog will
                appear to finish setting up the project properties.
            </p>
            <p>
                Go to the <strong>Project Execution</strong> tab, and setup
                <strong>Main File</strong> to <em>src/videoplayer.py</em>, and
                <strong>Python Path</strong> to the path of the Python
                executable, it can work either with Python 2 or Python 3, also
                you can set the parameters passed to your program with
                <strong>Params</strong>.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot019.png">
                    <img class="thumbnail"
                         alt="Set main file"
                         src="pics/snapshots/snapshot019.png" />
                </a>
            </p>
            <p>
                Like as we did with Qt Designer, we can test the functionality
                of the program, although as yet we have not written the
                functionality that will have each element within the interface,
                the program will not do anything.
            </p>
        </div>
        <div class="page">
            <h1><a name="menubuttons">
                Menu Buttons
            </a></h1>
            <p>
                Let's begin creating our first code interaction with the GUI.
            </p>
            <p>
                We will create a menu in which when user press the "Add Media"
                button, the button will show the options for add new files or a
                list of URLs. The menu must look like this:
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot020.png">
                    <img class="thumbnail"
                         alt="Add media menu"
                         src="pics/snapshots/snapshot020.png" />
                </a>
            </p>
            <p>
                Each widget in the GUI can be accessed using the object name
                defined in Qt Designer. PyQt automatically creates a reference
                to each one as a member of <strong>self</strong> object.
            </p>
            <p>
                For instance, if we want to access to the "Add Media" button you
                can access to it as:
            </p>
            <pre class="brush: py;">
                self.btnAddMedia.someWidgetMethod(arg1, arg2, ...)
            </pre>
            <p>
                The code below shows how to add a menu to a button:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 72-82
# Create a menu for adding new medias.
self.addMediaMenu = QtGui.QMenu()

# Add a new action to the menu and get a reference to it.
self.axnAddLocalFile = self.addMediaMenu.addAction(self.tr('Add local '
                                                           '&amp;File'))

self.axnAddURL = self.addMediaMenu.addAction(self.tr('Add &amp;URL'))

# Add the menu to the add media button.
self.btnAddMedia.setMenu(self.addMediaMenu)
            </pre>
            <p>
                Qt also allows you to load discs (CD, DVD, BlueRay, etc.) as
                playing medias, but we need to add specific code for each
                platform and that is out of this tutorial.
            </p>
        </div>
        <div class="page">
            <h1><a name="signalsandslots">
                Signals and slots
            </a></h1>
            <p>
                Now we will begin to receive events from the interface, that is,
                for instance when a button is pressed, you do a double click on
                the playlist, the video stops, etc..
            </p>
            <p>
                For this, we will use what in Qt are known as
                <strong>signals</strong> and <strong>slots</strong>.
            </p>
            <p>
                A <strong>signal</strong> is basically, a method to which
                objects methods that are interested on catch the event
                associated with that signal can be connected.
            </p>
            <p>
                A <strong>slot</strong> is a method that can be connected to
                a <strong>signal</strong> for catching and process the event
                associated with that <strong>signal</strong>.
            </p>
            <p>
                Any object that you want to implement <strong>signals</strong>
                and <strong>slots</strong> must inherit from
                <strong>QObject</strong> class, all Qt widgets you use do that,
                because they inherit from <strong>QWidget</strong>, and
                <strong>QWidget</strong> inherits from <strong>QObject</strong>.
                Qt widgets provides predefined signals and slots, but it is also
                possible to create a custom <strong>signals</strong> and
                <strong>slots</strong> to our own widgets.
            </p>
            <p>
                The <strong>slots</strong> are used to receive
                <strong>signals</strong>, but can also be used as normal
                functions. As an object does not know if a slot is capturing
                their signals, a slot does not know if have a signal connected
                to it. This ensures that truly independent components can be
                created with Qt.
            </p>
            <p>
                You can connect as many signals as you need to a single slot,
                and a signal can connected as many slots as you need. You can
                even connect a signal directly to another signal.
            </p>
            <p class="space"></p>
            <p>
                <a target="_blank"
                   href="http://qt-project.org/doc/latest/signalsandslots.html">
                    qt-project.org/doc/latest/signalsandslots.html
                </a>
            </p>
            <p class="space"></p>
            <p>
                To connect a slot to a signal, its general form is:
            </p>
            <pre class="brush: py;">
sender.signal.connect(slot_function)
            </pre>
            <p>
                Where <em>sender</em> is the object that sends the signal,
                <em>signal</em> is the name of the signal that you want to
                receive, <em>slot_function</em> is the slot that will receive
                the señal.
            </p>
            <p>
                For instance, if you want to receive the signal when the "About"
                button is pressed, you must do as follows:
            </p>
            <pre class="brush: py;">
self.btnAbout.clicked.connect(self.on_btnAbout_clicked)
            </pre>
            <p>
                Here the object that sends the sends the signal is
                <em>self.btnAbout</em>, the signal is <em>clicked</em>, and the
                slot is <em>self.on_ btnAbout_ clicked</em>.
            </p>
            <p>
                While not mandatory, the name of the slot should have the form
                below:
            </p>
            <pre>
on_sender_signal
            </pre>
            <p>
                You can create a slot using the form below:
            </p>
            <pre class="brush: py;">
@QtCore.Slot(argType1, argType2, ...)
def on_sender_signal(self, arg1, arg2, ...):
    ...
            </pre>
            <p>
                It may happen that an object send several signals of the same
                name but with different numbers and types of parameters. In that
                case we would like to filter those signals who match the desired
                parameters. We can filter it with decorators.
            </p>
            <p>
                Decorators are own of Python language, not Qt.
            </p>
            <p>
                A decorator is a function that receives another function as
                parameter (the function to decorate) and returns a new function
                (the decorated function).
            </p>
        </div>
        <div class="page">
            <p>
                The decorators are used generally for:
            </p>
            <ul>
                <li>
                    Modify the behavior of the original function.
                </li>
                <li>
                    Sometimes, save a lot when some code is repeated.
                </li>
                <li>
                    Parameters check.
                </li>
                <li>
                    Unitary tests.
                </li>
                <li>
                    Debugging.
                </li>
            </ul>
            <p>
                A very simple example of using decorators is as follows:
            </p>
            <pre class="brush: py;">
# Define the decorator function.
def decore_funcion(original_function):
    # Decorated function is defined inside decore function.
    # "args" and "kwargs" are the parameters that receives the original
    # function.
    def decorated_function(*args, **kwargs):
        # Here we can write all the code necessary to change the behavior of the
        # original function.
        # In this case we execute the original function and then print a
        # message.
        original_function(*args, **kwargs)
        print("This is the decorated function")

    # Return decorated function.
    return decorated_function

# Decorathe the original function.
@decore_funcion
def function():
    print("This is the original function")

function()
            </pre>
            <p>
                The output will be:
            </p>
            <pre>
> This is the original function
> This is the decorated function
            </pre>
            <p>
                For more information check this link:
            </p>
            <p class="space"></p>
            <p>
                <a target="_blank"
                   href="http://wiki.python.org/moin/PythonDecorators">
                    wiki.python.org/moin/PythonDecorators
                </a>
            </p>
            <p class="space"></p>
            <p>
                In PyQt, the slots are usually decorated, to filter the signals
                and types of data that we want to receive.
            </p>
            <p>
                PyQt also support the so called "slot autoconnection".
            </p>
            <p>
                Instead of connecting signals and slots manually as I said
                previously, you can connect by method names. For instance,
                you don't need to do this:
            </p>
            <pre class="brush: py;">
self.btnAbout.clicked.connect(self.on_btnAbout_clicked)
            </pre>
            <p>
                You just need to create the slot:
            </p>
            <pre class="brush: py;">
@QtCore.Slot()
def on_btnAbout_clicked(self):
    pass
            </pre>
            <p>
                That's all. The signal will be automatically connected to the
                slot with the <em>on_sender_signal</em> form.
            </p>
        </div>
        <div class="page">
            <p>
                Now we can create the slots to catch the GUI events..
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 290-291
@QtCore.pyqtSlot()
def on_btnClearPlayList_clicked(self):
    pass

# src/videoplayer.py: 298-299
@QtCore.pyqtSlot()
def on_btnFullscreen_clicked(self):
    pass

# src/videoplayer.py: 317-318
@QtCore.pyqtSlot()
def on_btnNext_clicked(self):
    pass

# src/videoplayer.py: 347-348
@QtCore.pyqtSlot()
def on_btnPlayPause_clicked(self):
    pass

# src/videoplayer.py: 370-371
@QtCore.pyqtSlot()
def on_btnPrevious_clicked(self):
    pass

# src/videoplayer.py: 402-403
@QtCore.pyqtSlot()
def on_btnRemoveMedia_clicked(self):
    pass

# src/videoplayer.py: 414-415
@QtCore.pyqtSlot()
def on_btnRepeatPlayList_clicked(self):
    pass

# src/videoplayer.py: 419-420
@QtCore.pyqtSlot()
def on_btnVideoFill_clicked(self):
    pass

# src/videoplayer.py: 434-435
@QtCore.pyqtSlot()
def on_btnShowPlayList_clicked(self):
    pass

# src/videoplayer.py: 439-490
@QtCore.pyqtSlot()
def on_btnShufflePlayList_clicked(self):
    pass

# src/videoplayer.py: 465-466
@QtCore.pyqtSlot(QtCore.QModelIndex)
def on_lswPlaylist_doubleClicked(self, model_index):
    pass
            </pre>
            <p>
                Also we must create and connect the slots for the menu actions.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 84-90
# When user choose an option from the menu, this action will emit the
# "triggered" signal, this signal will be connected to his respective
# slot.
self.axnAddLocalFile.triggered.\
                        connect(self.on_axnAddLocalFile_triggered)

self.axnAddURL.triggered.connect(self.on_axnAddURL_triggered)

# src/videoplayer.py: 257-258
@QtCore.pyqtSlot()
def on_axnAddLocalFile_triggered(self):
    pass

# src/videoplayer.py: 268-269
@QtCore.pyqtSlot()
def on_axnAddURL_triggered(self):
    pass
            </pre>
        </div>
        <div class="page">
            <p>
                Finally, the last way in which we can connect signals and slots
                is using Qt Designer, this way is useful when you need to
                connect them internally. In Qt Designer, press the button
                "Edit Signals/Slots", then drag and drop from the widget that
                emits the signal to the widget that will receive that signal.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot021.png">
                    <img class="thumbnail"
                         alt="Slots&amp;signals in Qt Designer"
                         src="pics/snapshots/snapshot021.png" />
                </a>
            </p>
            <p>
                Immediately appears a dialog showing all signals and slots
                available to connect.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot022.png">
                    <img class="thumbnail-75"
                         alt="Slots connection dialog"
                         src="pics/snapshots/snapshot022.png" />
                </a>
            </p>
            <p>
                This is very handy because we can connect all signals and slots
                without writing any code.
            </p>
        </div>
        <div class="page">
            <h1><a name="addfilesplaylist">
                Add files to the playlist
            </a></h1>
            <p>
                Now let's create a list where we will store the files to play.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 61-62
# A list of phonon.Phonon.MediaSource.
self.playlist = []
            </pre>
            <p>
                This list will be a copy of the list you will see in the
                <strong>QListWidget</strong>.
            </p>
            <p>
                The question is: Which data type will store on the list?. To
                answer this question we must first know what type of data is
                needs <strong>phonon::VideoPlayer</strong> to play media and
                with what data type we will populate the
                <strong>QListWidget</strong>.
            </p>
            <p>
                <strong>Phonon::VideoPlayer</strong> offers the following
                methods to load and play the medias:
            </p>
            <p class="space"></p>
            <p>
                <a target="_blank"
                   href="http://qt-project.org/doc/latest/phonon-videoplayer.html#load">
                    phonon.VideoPlayer.load(phonon.MediaSource source)
                </a>
            </p>
            <p>
                <a target="_blank"
                   href="http://qt-project.org/doc/latest/phonon-videoplayer.html#play">
                    phonon.VideoPlayer.play(phonon.MediaSource source)
                </a>
            </p>
            <p>
                <a target="_blank"
                   href="http://qt-project.org/doc/latest/phonon-videoplayer.html#play-2">
                    phonon.VideoPlayer.play()
                </a>
            </p>
            <p class="space"></p>
            <p>
                According to the official Qt documentation, we can load a medium
                with
                <strong>phonon.Videoplayer.load(phonon.MediaSource)</strong> and
                then play with <strong>phonon.Videoplayer.play()</strong>, or we
                can load and play the media directly with
                <strong>phonon.Videoplayer.load(phonon.MediaSource)</strong>,
                in both cases the parameter required to play the media is
                <a target="_blank"
                   href="http://qt-project.org/doc/latest/phonon-mediasource.html">
                    phonon.MediaSource
                </a>.
            </p>
            <p>
                Now let's see what parameters need <strong>phonon.MediaSource</strong>:
            </p>
            <p class="space"></p>
            <p>
                <a target="_blank"
                   href="http://qt-project.org/doc/latest/phonon-mediasource.html#MediaSource">
                    phonon.MediaSource.MediaSource(QtCore.QString fileName)
                </a>
            </p>
            <p>
                <a target="_blank"
                   href="http://qt-project.org/doc/latest/phonon-mediasource.html#MediaSource-3">
                    phonon.MediaSource.MediaSource(QtCode.QUrl url)
                </a>
            </p>
            <p class="space"></p>
            <p>
                We only want to load files and URLs. In the first constructor,
                we use the file path to play, the variable must be of
                <strong>QtCore.QString</strong>, and thats equivalent to the
                <em>str</em> type of Python. In the second constructor we use
                the web address to play it, the variable is of
                <strong>QtCore.QUrl</strong> type which in turn is initialized
                with a <em>str</em> type parameter.
            </p>
            <p>
                Now let's see what methods offers us
                <strong>QListWidget</strong> to add items to the list.
            </p>
            <p class="space"></p>
            <p>
                <a target="_blank"
                   href="http://qt-project.org/doc/latest/qlistwidget.html#addItems">
                    QtGui.QListWidget.addItems(QStringList labels)
                </a>
            </p>
            <p class="space"></p>
            <p>
                A <strong>QStringList</strong> is nothing more than a list of
                strings, a variable of <em>list</em> type with elements of
                <em>str</em> type.
            </p>
            <p>
                So to add medias to the playlist we will use a list of strings,
                that will contains the names of files and URLs.
            </p>
            <p>
                Therefore, <em>self.playlist</em> will store elements of
                <strong>phonon.MediaSource</strong> type.
            </p>
            <p>
                To add files to playlist, add the following code to
                <em>on_axnAddLocalFile_triggered</em>:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 257-266
@QtCore.pyqtSlot()
def on_axnAddLocalFile_triggered(self):
    # Open the file selection dialog.
    # The first parameter stablish MainWindow as the parent of the dialog,
    # and the second sets the dialog title.
    filenames = QtGui.QFileDialog.\
                        getOpenFileNames(self, self.tr('Add local files'))

    # Add the filenames to the file names to the playlist.
    self.addMedias(filenames)
            </pre>
        </div>
        <div class="page">
            <p>
                Import the <em>os</em> module:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 23-23
import os
            </pre>
            <p>
                Define the <em>self.addMedias</em> method:
            </p>
            <pre class="brush: py;">
# scr/videoplayer.py: 228-255
def addMedias(self, medias=[]):
    # Sort the media list alphabetically.
    medias.sort()

    # We assume that we aren't playing any media.
    play = False

    # If user chose at least one media...
    if medias != []:
        # If the playlist is empty, and there aren't a media playing.
        if self.playlist == []:
            play = True

        # Populate the playlist.
        for media in medias:
            if media.startswith('http://') or media.startswith('mms://'):
                self.playlist += [phonon.Phonon.\
                                            MediaSource(QtCore.QUrl(media))]
            else:
                self.playlist += [phonon.Phonon.MediaSource(media)]

        self.updatePlayList()

    # If the playlist has been loaded and there aren't a media playing...
    if play and \
        self.vdpVideo.mediaObject().state() != phonon.Phonon.PlayingState:
        # play it.
        self.on_btnPlayPause_clicked()
            </pre>
            <p>
                Now, define the <em>self.updatePlayList</em> method, this will
                update the playlist when the user adds a new media.
            </p>
            <pre class="brush: py;">
# scr/videoplayer.py: 135-155
# This method updates the playlist when user adds a new media.
def updatePlayList(self):
    # Create an empty playlist.
    playlist = []

    # For each media to play...
    for source in self.playlist:
        # If the media is a local file...
        if source.type() == phonon.Phonon.MediaSource.LocalFile:
            # Just add the name of the file without the path.
            playlist += [os.path.basename(str(source.fileName()))]
        # If the media is an URL...
        elif source.type() == phonon.Phonon.MediaSource.Url:
            # Add the URL to the list.
            playlist += [str(source.url().toString())]

    # Remove all items in QListWidget
    self.lswPlaylist.clear()

    # add the new playlist.
    self.lswPlaylist.addItems(playlist)
            </pre>
        </div>
        <div class="page">
            <h1><a name="playfiles">
                Play files
            </a></h1>
            <p>
                Now, let's add the code to play the media files. First, we need
                to connect <strong>phonon::VideoPlayer</strong> with the volume
                and time sliders.
            </p>
            <p>
                Add the following code to <em>__ init__()</em>:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 106-111
# We connect the audio slider to the video player.
# Doing this we can control the time position of the video or music.
self.sldVolumeSlider.setAudioOutput(self.vdpVideo.audioOutput())

# Connect the volume slider to the video player.
self.sldSeekSlider.setMediaObject(self.vdpVideo.mediaObject())
            </pre>
            <p>
                Add the following code to play a media by double clicking on an
                item from the list.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 462-469
# When the user do a doble click on an item in QListWidget, it emits the
# "doubleClicked" signal, and pass a reference to the clicked item as
# parameter, which is a QtGui.QListWidgetItem type.
@QtCore.pyqtSlot(QtCore.QModelIndex)
def on_lswPlaylist_doubleClicked(self, model_index):
    # If the playlist is empty, do nothing.
    if self.playlist == []:
        return

    # src/videoplayer.py: 478-478
    self.vdpVideo.play(self.playlist[self.lswPlaylist.row(model_index)])
            </pre>
            <p>
                Now you can load some files to the playlist and double click on
                any of them to play, also you can control the volume and playing
                time, and can also stop the playback with the <em>Stop</em>
                button.
            </p>
        </div>
        <div class="page">
            <h1><a name="timers">
                Using timers
            </a></h1>
            <p>
                Now we will use the <strong>QLabel</strong> that we had created
                in Qt Designer to display the current playing time, for it will
                create a timer that every so often pick the current timestamp of
                the media.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 117-129
# Create a timer for update the playtime of the current media and
# the mouse status.
self.tmrTimer = QtCore.QTimer(self)

# The timer will emit the "timeout" signal every a quarter of second.
self.tmrTimer.setInterval(250)

# When it reaches the stablished time, the timer will emit the "timeout"
# signal and it respective slot is called.
self.tmrTimer.timeout.connect(self.on_tmrTimer_timeout)

# Starts the timer.
self.tmrTimer.start()
            </pre>
            <p>
                Finally we add the <em> on_tmrTimer_timeout</em> slot:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 480-508
@QtCore.pyqtSlot()
def on_tmrTimer_timeout(self):
    # First update the playtime.

    # Gte the current time mark,
    currentTime = self.vdpVideo.currentTime()

    if currentTime == 0:
        # If the current playtime is 0 seconds, clear the label text.
        self.lblTime.setText('')
    else:
        # Get the total playtime of the media.
        totalTime = self.vdpVideo.totalTime()

        # If the total playtime is less than 1 hour, just show minutes
        # and seconds.
        tFormat = 'mm:ss' if totalTime &lt; 3600000 else 'hh:mm:ss'

        # We use Qtime for time convertions.
        currentTimeH = QtCore.QTime()

        # Convert times to a human readable strings.
        ct = currentTimeH.addMSecs(currentTime).toString(tFormat)

        totalTimeH = QtCore.QTime()
        tt = totalTimeH.addMSecs(totalTime).toString(tFormat)

        # Set time to label.
        self.lblTime.setText(ct + '/' + tt)
            </pre>
        </div>
        <div class="page">
            <h1><a name="fullscreen">
                Go fullscreen
            </a></h1>
            <p>
                There is nothing better than seeing a movie on a screen as large
                as possible, for it we will add options to put the window in
                fullscreen mode.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 298-315
@QtCore.pyqtSlot()
def on_btnFullscreen_clicked(self):
    # If the window is currently in fullscreen mode...
    if self.isFullScreen():
        # show it in normal mode.
        self.showNormal()

        # Show the playlist.
        self.dckPlayList.show()
    else:
        # show it in fullscreen mode.
        self.showFullScreen()

        # Hide the playlist.
        self.dckPlayList.hide()

        # Hide the mouse cursor.
        self.setCursor(QtGui.QCursor(QtCore.Qt.BlankCursor))
            </pre>
            <p>
                In fullscreen mode we must hide the mouse cursor, the controls
                bar, and the playlist.
            </p>
            <p>
                If the user moves the mouse, it must be unhidden and stay
                visible arround 1 second, to hide it again.
            </p>
            <p>
                When the mouse approaches to the controls bar area, the controls
                bar will be unhidden, When the mouse leaves the controls bar
                area, the controls bar will be hidden again.
            </p>
            <p>
                When user exits from full fullscreen mode, the mouse cursor, the
                controls bar, and the playlist will be shown again.
            </p>
            <p>
                First, initialize the current mouse position and time.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 131-133
# Stores a reference to the position and the current time.
self.mousePos0 = QtGui.QCursor.pos()
self.mouseT0 = QtCore.QTime.currentTime()
            </pre>
        </div>
        <div class="page">
            <p>
                Then, add the following code to <em>on_tmrTimer_timeout()</em>:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 510-557
# Now update the mouse status.

# The window is in fullscreen mode...
if self.isFullScreen():
    # Update the current mouse time and position.
    mousePos = QtGui.QCursor.pos()
    mouseT = QtCore.QTime.currentTime()

    # Normally, when the program is in fullscreen mode, the mouse must
    # be hidden until user move it.
    if (mousePos != self.mousePos0 and \
        self.cursor().shape() == QtCore.Qt.BlankCursor) or \
        self.wdgVideoControls.isVisible():
        self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))

        # Reset the time count for calculating the mouse moving time.
        self.mouseT0 = QtCore.QTime.currentTime()
    # If user stops moving the mouse, it must stay visible at least some
    # seconds.
    elif self.cursor().shape() == QtCore.Qt.ArrowCursor and \
            self.mouseT0.secsTo(mouseT) > 1:
        self.setCursor(QtGui.QCursor(QtCore.Qt.BlankCursor))

    # Update the current mouse position.
    self.mousePos0 = mousePos

    # Convert the global mouse position in the screen to the window
    # local coordinates. And get the coordinate for Y axis.
    mouseY = self.mapFromGlobal(mousePos).y()

    # If the mouse approaches to the position in which must be the
    # controls bar, it must be unhidden.
    if mouseY &lt; self.height() and \
        mouseY > self.height() - self.wdgVideoControls.height():
        if self.wdgVideoControls.isHidden():
            self.wdgVideoControls.show()
    # otherwise it must stay hidden.
    elif self.wdgVideoControls.isVisible():
        self.wdgVideoControls.hide()
# The window is in normal mode...
else:
    # If the mouse cursor is hidden, show it.
    if self.cursor().shape() == QtCore.Qt.BlankCursor:
        self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))

    # Show playlist.
    if self.wdgVideoControls.isHidden():
        self.wdgVideoControls.show()
            </pre>
            <p>
                Also, we can add code to set the window in fullscreen mode when
                user double click en the video.
            </p>
            <p>
                We will made use of the
                <a target="_blank"
                   href="http://qt-project.org/doc/latest/qwidget.html#mouseDoubleClickEvent">
                    mouseDoubleClickEvent()
                </a> protected function to catch that event.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 157-161
# mouseDoubleClickEvent is a protected method which called when user does
# doble click in the GUI and this event isn't catched by anyother widget.
def mouseDoubleClickEvent(self, event):
    # Always, before process the event, we must send a copy of it to the
    # ancestor class.
    QtGui.QMainWindow.mouseDoubleClickEvent(self, event)

    # Go to fullscreen mode or exit from it.
    self.on_btnFullscreen_clicked()
            </pre>
        </div>
        <div class="page">
            <h1><a name="aspectratio">
                Video aspect ratio
            </a></h1>
            <p>
                Some people prefer to see the video in its original dimensions,
                which means that when the proportions of the video do not match
                the proportions of the window or screen, the video shows with
                black bars on the sides, but others prefer the video to fills
                the video widget regardless of size, which means there may be a
                slight disproportionality in the image, the image is elongated.
            </p>
            <p>
                To change the video aspect ratio, use the following code:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 419-432
@QtCore.pyqtSlot()
def on_btnVideoFill_clicked(self):
    # If the btnVideoFill button is checked, the video will be stretched to
    # fill the entire video widget.
    # otherwise, the video will be preserve it's aspect ratio.
    if self.vdpVideo.videoWidget().aspectRatio() == \
        phonon.Phonon.VideoWidget.AspectRatioWidget:
        self.vdpVideo.videoWidget().\
                        setAspectRatio(phonon.Phonon.VideoWidget.\
                                                    AspectRatioAuto)
    else:
        self.vdpVideo.videoWidget().\
                        setAspectRatio(phonon.Phonon.VideoWidget.\
                                                    AspectRatioWidget)
            </pre>
        </div>
        <div class="page">
            <h1><a name="playpause">
                Play and pause
            </a></h1>
            <p>
                Now add the functionality to play and pause the media.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 347-368
@QtCore.pyqtSlot()
def on_btnPlayPause_clicked(self):
    # If we are playing a media...
    if self.vdpVideo.mediaObject().state() == phonon.Phonon.PlayingState:
        # pause it.
        self.vdpVideo.pause()
    # If the current media is paused...
    elif self.vdpVideo.mediaObject().state() == phonon.Phonon.PausedState:
        # play it.
        self.vdpVideo.play()
    # If there aren't a selected media in the playlist...
    elif self.lswPlaylist.currentRow() &lt; 0:
        # Select the first item in the list.
        self.lswPlaylist.setCurrentRow(0, QtGui.QItemSelectionModel.\
                                                SelectCurrent)

        # call to the on_lswPlayList_doubleClicked slot to play the media.
        self.on_lswPlaylist_doubleClicked(self.lswPlaylist.currentItem())
    # If there are at least one item selected...
    else:
        # call to the on_lswPlayList_doubleClicked slot to play it.
        self.on_lswPlaylist_doubleClicked(self.lswPlaylist.currentItem())
            </pre>
            <p>
                Also modify the <em>on_lswPlaylist_doubleClicked</em> slot,
                because the parameters with which we will call this slot are
                different from how we had defined.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 462-478
# When the user do a doble click on an item in QListWidget, it emits the
# "doubleClicked" signal, and pass a reference to the clicked item as
# parameter, which is a QtGui.QListWidgetItem type.
@QtCore.pyqtSlot(QtCore.QModelIndex)
def on_lswPlaylist_doubleClicked(self, model_index):
    # If the playlist is empty, do nothing.
    if self.playlist == []:
        return

    try:
        # Get the index of model_view, use it to obtain the corresponding
        # MediaSource, and then play it.
        # Here model_index is of the type QtGui.QListWidgetItem.
        self.vdpVideo.play(self.playlist[model_index.row()])
    except:
        # Here model_index is of the type QtGui.QModelIndex.
        self.vdpVideo.play(self.playlist[self.lswPlaylist.row(model_index)])
            </pre>
        </div>
        <div class="page">
            <h1><a name="shufflerepeat">
                Shuffle and repeat the playlist
            </a></h1>
            <p>
                No one multimedia player who prides of it, can't lack the
                classic options of repeat and shuffle the playlist.
            </p>
            <p>
                We will add some variables in <em>__init__</em> to control
                these states.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 64-70
# This will be a copy of the playlist before shuffling.
self.playlistTmp = []

# This flag indicates that when the program reach the end of the
# playlist, start playing all the playlist again from beginning, or if
# we are at the beginning of the playlist, go to the last media.
self.repeat = False
            </pre>
            <p>
                First let's see how to shuffle the playlist, we must add the
                <em>random</em> module:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 28-29
# "ramdom" module is used for mezclar playlist shuffling.
import random
            </pre>
            <p>
                And finally add the following code:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 439-460
@QtCore.pyqtSlot()
def on_btnShufflePlayList_clicked(self):
    # If the playlist is empty...
    if self.playlistTmp == []:
        # The temporal playlist will be a copy of the current playlist.
        self.playlistTmp = self.playlist[:]

        # get number of items in the list.
        items = len(self.playlist)

        # Sort the list randomly.
        self.playlist = [self.playlist.pop(
                            random.randint(0, len(self.playlist) - 1))
                            for index in range(items)]
    else:
        # Return the playlist to it's original state.
        self.playlist = self.playlistTmp[:]

        # and clear the temporal playlist.
        self.playlistTmp = []

    self.updatePlayList()
            </pre>
            <p>
                The <em>self.repeat</em> flag will be needed when we activate
                the forward and backward functions. So now just add the
                functionality to modify the flag with the following code:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 414-417
@QtCore.pyqtSlot()
def on_btnRepeatPlayList_clicked(self):
    # Toggle on/off repeat mode.
    self.repeat = not self.repeat
            </pre>
        </div>
        <div class="page">
            <h1><a name="seekmedia">
                Move forward and backward the medias
            </a></h1>
            <p>
                Now add the functionality to play the following media.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 317-345
@QtCore.pyqtSlot()
def on_btnNext_clicked(self):
    if self.playlist == []:
        return

    # Get a reference of the current selected media.
    curIndex = self.lswPlaylist.currentRow()

    # If the current selected media index is less than the size of the
    # playlist...
    if curIndex + 1 &lt; len(self.playlist):
        # increase the index of the current media.
        index = curIndex + 1
    # If the current selected media index is greater than the size of the
    # playlist...
    else:
        # If the repeat mode isn't selected then do nothing.
        if not self.repeat:
            return

        # otherwise, the next media to play will be the first in the list.
        index = 0

    # Select the next media in the playlist
    self.lswPlaylist.setCurrentRow(index,
                                    QtGui.QItemSelectionModel.SelectCurrent)

    # and play it.
    self.on_lswPlaylist_doubleClicked(self.lswPlaylist.item(index))
            </pre>
            <p>
                We do the same to switch to the previous media.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 370-400
@QtCore.pyqtSlot()
def on_btnPrevious_clicked(self):
    if self.playlist == []:
        return

    # Get a reference of the current selected media.
    curIndex = self.lswPlaylist.currentRow()

    # Sí cur_index - 1 es mayor o igual que el primer ítem de la lista de
    # reproducción...
    # If the current selected media index is greater or equal to the first
    # index of the playlist...
    if curIndex - 1 >= 0:
        # decrease the index of the current media.
        index = curIndex - 1
    # If the current selected media index is less than the first item of the
    # playlist...
    else:
        # If the repeat mode isn't selected then do nothing.
        if not self.repeat:
            return

        # otherwise, the next media to play will be the last in the list.
        index = len(self.playlist) - 1

    # Select the previous media in the playlist
    self.lswPlaylist.setCurrentRow(index,
                                    QtGui.QItemSelectionModel.SelectCurrent)

    # and play it.
    self.on_lswPlaylist_doubleClicked(self.lswPlaylist.item(index))
            </pre>
        </div>
        <div class="page">
            <h1><a name="clearplaylist">
                Removing the medias from playlist
            </a></h1>
            <p>
                This is the code to delete only the selected items in the list.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 402-412
@QtCore.pyqtSlot()
def on_btnRemoveMedia_clicked(self):
    # For each selected media...
    for media in self.lswPlaylist.selectedItems():
        try:
            # get it's index and remove it from the playlist.
            del self.playlist[self.lswPlaylist.row(media)]
        except:
            pass

    self.updatePlayList()
            </pre>
            <p>
                And this is the code to clear the entire playlist.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 290-296
@QtCore.pyqtSlot()
def on_btnClearPlayList_clicked(self):
    # Clear the original and temporal playlist.
    self.playlist = []
    self.playlistTmp = []

    self.updatePlayList()
            </pre>
        </div>
        <div class="page">
            <h1><a name="addurlplaylist">
                Add URLs to the playlist
            </a></h1>
            <p>
                Vamos a crear un diálogo personalizado en el que el usuario
                puede añadir varias direcciones URL al mismo tiempo.
            </p>
            <p>
                Go to Qt Designer and create a <strong>Dialogs With Buttons
                Bottom</strong> dialog that may looks like this:
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot023.png">
                    <img class="thumbnail-75"
                         alt="Add URL dialog"
                         src="pics/snapshots/snapshot023.png" />
                </a>
            </p>
            <p>
                We can add or remove buttons to the
                <strong>QDialogButtonBox</strong> from the Property Editor with
                the <strong>standardButtons</strong> property.
            </p>
            <p>
                In our case, we only need the <em>Ok</em> and <em>Cancel</em>
                buttons.
            </p>
            <p>
                Also, <strong>modal</strong> dialog property must be marked, so
                that when called, blocks the window that called it.
            </p>
            <p>
                We will add it to the <em>share/ui</em> folder with
                <em>addurl.ui</em> as name and also create the file
                <em>src/addurl.py</em>.
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot024.png">
                    <img alt="Project structure"
                         class="thumbnail"
                         src="pics/snapshots/snapshot024.png" />
                </a>
            </p>
        </div>
        <div class="page">
            <p>
                In <em>addurl.py</em> add the following code, I will comment
                only new parts, since most have already been explained above.
            </p>
            <pre class="brush: py;">
# src/addurl.py: 23-74
import sys

from PyQt4 import QtCore, QtGui, uic


class AddURL(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)

        uic.loadUi('../share/ui/addurl.ui', self)

        # We store all URLs added by the user in a list.
        self.urls = []

        # When the user click the "Ok" button..
        self.bbxAcceptCancel.accepted.connect(self.on_bbxAcceptCancel_accepted)

        # When the user click the "Cancel" button..
        self.bbxAcceptCancel.rejected.connect(self.on_bbxAcceptCancel_rejected)

    @QtCore.pyqtSlot()
    def on_bbxAcceptCancel_accepted(self):
        # Read the text from QPlainTextEdit.
        # Each line is an URL.
        # I don't add url checking for no complicating the code.
        self.urls = str(self.txtURLList.toPlainText()).split()

        # Sort the URL list.
        self.urls.sort()

        # Close the dialog and return 0, this means that the user accepted the
        # action.
        self.done(0)

    @QtCore.pyqtSlot()
    def on_bbxAcceptCancel_rejected(self):
        # Close the dialog and return 1, this means that the user cancelled the
        # action.
        self.done(1)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)

    translator = QtCore.QTranslator(app)
    locale = QtCore.QLocale.system().name()
    translator.load(locale + '.qm', '../share/ts')
    app.installTranslator(translator)

    add_url = AddURL()
    add_url.show()
    app.exec_()
            </pre>
            <p>
                Add the module to <em>videoplayer.py</em>.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 46-47
# Import the modules with the dialog of our program.
import addurl
            </pre>
        </div>
        <div class="page">
            <p>
                Finally, define the <em>on_axnAddURL_triggered</em> slot.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 267-279
@QtCore.pyqtSlot()
def on_axnAddURL_triggered(self):
    # Create an instance for the "Add URL" dialog.
    addURLDlg = addurl.AddURL(self)

    # Open the dialog.
    # The program execution will stop here until user close the dialog.
    addURLDlg.exec_()

    if addURLDlg.result() == 0:
        # Add the URLs to the playlist.
        self.addMedias(addURLDlg.urls)
            </pre>
            <p>
                Finally the result will be this:
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot025.png">
                    <img class="thumbnail"
                         alt="Final Add URL dialog"
                         src="pics/snapshots/snapshot025.png" />
                </a>
            </p>
        </div>
        <div class="page">
            <h1><a name="about">
                The "About" dialog
            </a></h1>
            <p>
                Finally, we will create two <strong>About</strong> dialogs, one
                for our program and other for Qt. First, start creating a new
                menu for the <strong>About</strong> button.
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 92-104
# Create a menu for the "About" button.
self.aboutMenu = QtGui.QMenu()

# Add the actions to the menu and get a reference to it.
self.axnAbout = self.aboutMenu.addAction(self.tr('About this &amp;Program'))
self.axnAboutQt = self.aboutMenu.addAction(self.tr('About &amp;Qt'))

# Add the menu to the "About" button.
self.btnAbout.setMenu(self.aboutMenu)

# Connect the signals.
self.axnAbout.triggered.connect(self.on_axnAbout_triggered)
self.axnAboutQt.triggered.connect(self.on_axnAboutQt_triggered)
            </pre>
            <p>
                And connect the slot.
            <p>
            <pre class="brush: py;">
# src/videoplayer.py: 281-282
@QtCore.pyqtSlot()
def on_axnAbout_triggered(self):
    pass

# src/videoplayer.py: 286-287
@QtCore.pyqtSlot()
def on_axnAboutQt_triggered(self):
    pass
            </pre>
            <p>
                Now, we will design the about dialog for our program.
            </p>
            <p>
                The information that will contain the dialog depends on the
                likes and needs of the software designer. For example, we may
                place information of the license, any image identifying the
                program, information on how to use the program, commands, etc..
            </p>
            <p>
                In our case with something simple will be enough, anyway, is
                just an example.
            </p>
            <p>
                In Qt Designer, create a <strong>Dialog With Buttons
                Bottom</strong> as below:
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot026.png">
                    <img class="thumbnail-75"
                         alt="Designing About dialog"
                         src="pics/snapshots/snapshot026.png" />
                </a>
            </p>
            <p>
                Connect the <strong>accepted</strong> signal emitted by
                <strong>buttonBox</strong>, to the <strong>accept</strong> slot
                belonging to the dialogue (connection to ground).
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot027.png">
                    <img class="thumbnail"
                         alt="Connecting signals to ground"
                         src="pics/snapshots/snapshot027.png" />
                </a>
            </p>
        </div>
        <div class="page">
            <p>
                Create a new file called <em>aboutdlg.py</em> and put the
                following code, there is no need to explain the code, because
                this is the basic template:
            </p>
            <pre class="brush: py;">
# src/aboutdlg.py: 23-45
import sys

from PyQt4 import uic, QtGui, QtCore


class About(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)

        uic.loadUi('../share/ui/aboutdlg.ui', self)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)

    translator = QtCore.QTranslator(app)
    locale = QtCore.QLocale.system().name()
    translator.load(locale + '.qm', '../share/ts')
    app.installTranslator(translator)

    about = About()
    about.show()
    app.exec_()
            </pre>
            <p>
                The project structure must be like this:
            </p>
            <p class="thumbnail">
                <a target="_blank"
                   href="pics/snapshots/snapshot028.png">
                    <img class="thumbnail"
                         alt="Project structure"
                         src="pics/snapshots/snapshot028.png" />
                </a>
            </p>
            <p>
                And finally add the following code to call the dialog when the
                user presses the <strong>About</strong> button:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 281-284
@QtCore.pyqtSlot()
def on_axnAbout_triggered(self):
    about = aboutdlg.About(self)
    about.exec_()
            </pre>
            <p>
                Qt provides his own <strong>About</strong> dialog that shows the
                current Qt version used to run the program. You can call this
                dialog with the <strong>aboutQt</strong> static method provided
                by the <strong>QMessageBox</strong> class.
            </p>
            <p class="space"></p>
            <p>
                <a target="_blank"
                   href="http://qt-project.org/doc/qt-4.8/qmessagebox.html#aboutQt">
                    QMessageBox.aboutQt(QWidget parent, QString title)
                </a>
            </p>
            <p class="space"></p>
            <p>
                Add the following code to call this dialog:
            </p>
            <pre class="brush: py;">
# src/videoplayer.py: 286-288
@QtCore.pyqtSlot()
def on_axnAboutQt_triggered(self):
    QtGui.QMessageBox.aboutQt(self, self.tr('About Qt'))
            </pre>
        </div>
        <div class="page">
            <h1><a name="stylesheets">
                Using stylesheets
            </a></h1>
            <p>
                In progress
            </p>
        </div>
        <div class="page">
            <h1><a name="internationalisation">
                Internationalisation
            </a></h1>
            <p>
                In progress
            </p>
            <p>
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/i18n.html

In the root directory of the project run:

    pylupdate4 Webcamoid.pro

Then a _contents/ts/lang.ts_ will be created. Translate that file to your language using Qt Linguist, and change _lang.ts_ to your code language, for instance, if you speak Spanish call it _es.ts_. Then run the following command:

    lrelease contents/ts/lang.ts
            </p>
        </div>
        <div class="page">
            <h1><a name="relatedlinks">
                Links of interest
            </a></h1>
            <ul>
                <li>
                    The <a target="_blank"
                           href="http://qt-project.org/">
                            Qt Developer Network
                        </a>,
                    is the official and main Qt developers community.
                </li>
                <li>
                    The official documentation for
                    <a target="_blank"
                       href="http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/index.html">
                        PyQt
                    </a>
                    where you can found many examples of this binding.
                </li>
            </ul>
        </div>
    </body>
</html>
